﻿using psafth.RCTiming.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace psafth.RCTiming.Main
{
    public class RaceClassGroup
    {
        public List<EventParticipant> Competitors
        {
            get;
            set;
        }

        public RaceClass RaceClass
        {
            get;
            set;
        }

        public int NumberOfHeats
        {
            get;
            set;
        }

        public int HeatDuration
        {
            get;
            set;
        }

        public int FinalDuration
        {
            get;
            set;
        }
    }

    public class HeatHelper
    {
        public static List<T> ShuffleDrivers<T>(List<T> collection)
        {
            RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
            int n = collection.Count();
            while (n > 1)
            {
                byte[] box = new byte[1];
                do provider.GetBytes(box);
                while (!(box[0] < n * (Byte.MaxValue / n)));
                int k = (box[0] % n);
                n--;
                T value = collection[k];
                collection[k] = collection[n];
                collection[n] = value;
            }

            return collection;
        }

        public static void MakeHeats(ref Event evnt, List<RaceClassGroup> rcgs, bool randomize)
        {
            // Group the participants by their race class
            foreach (IEnumerable<EventParticipant> group in evnt.Participants.GroupBy(r => r.RaceClassId))
            {
                RaceClassGroup tmpGroup = new RaceClassGroup();

                tmpGroup.Competitors = group.ToList();
                if (tmpGroup.Competitors != null)
                    tmpGroup.RaceClass = tmpGroup.Competitors.FirstOrDefault().RaceClass;

                RaceClassGroup rcg = rcgs.FirstOrDefault(r => r.RaceClass.Id == tmpGroup.RaceClass.Id);

                decimal totalNumberOfDrivers = tmpGroup.Competitors.Count();
                decimal maxNumbPerheat = 12;

                decimal modulo = totalNumberOfDrivers % maxNumbPerheat;

                decimal highestNumberInLastHeat = 6;

                if (modulo > 0)
                {
                    for (int t = 12; t >= 4; t--)
                    {
                        decimal mod = totalNumberOfDrivers % t;

                        if (mod > highestNumberInLastHeat)
                        {
                            highestNumberInLastHeat = mod;
                            maxNumbPerheat = t;
                        }
                    }
                }

                decimal numberOfGroups = Math.Ceiling(totalNumberOfDrivers / maxNumbPerheat);
                decimal numberPerGroup = Math.Floor(totalNumberOfDrivers / numberOfGroups);

                if (randomize)
                    tmpGroup.Competitors = new List<EventParticipant>(ShuffleDrivers(tmpGroup.Competitors));

                int regIndex = 0;

                for (int k = 0; k < numberOfGroups; k++)
                {
                    List<HeatCompetitor> heatCompetitors = new List<HeatCompetitor>();

                    for (int j = 0; j <= numberPerGroup; j++)
                    {
                        heatCompetitors.Add(new HeatCompetitor(tmpGroup.Competitors[regIndex].Driver, tmpGroup.Competitors[regIndex].TransponderId)
                        {
                            StartNumber = j + 1,
                        });

                        regIndex++;

                        if (regIndex == totalNumberOfDrivers)
                        {
                            regIndex = 0;
                            break;
                        }
                    }

                    for (int hn = 1; hn <= rcg.NumberOfHeats; hn++)
                    {
                        string heatName = string.Format("Heat {0}", hn);

                        Heat h = new Heat()
                        {
                            Duration = rcg.HeatDuration,
                            Name = heatName,
                            Group = k + 1,
                            HeatCompetitors = new ObservableCollectionExt<HeatCompetitor>(heatCompetitors),
                            RaceClass = rcg.RaceClass
                        };

                        if (h.HeatCompetitors.Count > 0 && h.Duration > 0)
                            evnt.Heats.Add(h);
                    }
                }
            }


            //// For each heatsheet. Create heat(s).
            //    for (int i = 2; i <= workBook.Sheets.Count; i++)
            //    {
            //        if (workBook.Sheets[i].Visible < 0)
            //        {
            //            Excel.Worksheet currentWorksheet = workBook.Sheets[i];

            //            List<HeatDriver> registeredDrivers = GetHeatDrivers(currentWorksheet);

            //        }
            //    }

            //    try
            //    {

            //        _db.SaveChanges();

            //    }
            //    catch (DbEntityValidationException dbEx)
            //    {
            //        foreach (var validationErrors in dbEx.EntityValidationErrors)
            //        {
            //            foreach (var validationError in validationErrors.ValidationErrors)
            //            {
            //                Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
            //            }
            //        }
            //    }
            //    UpdateHeatsPanel();
            //}
        }
    }
}
